// *************************************************************************************************
//
// MK3D Engine
// --------------------------------------
// Copyright (C) 2007-2011 Zeb (mailto: zebbey@gmail.com)
//
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// *************************************************************************************************

#include "mk_header.h"
#include "mk_d3d9_shader.h"
#include "mk_engine.h"
#include "mk_error.h"
#include "mk_d3d9_texture.h"
#include "mk_d3d9_render_device.h"
#include "mk_memory_block.h"
#include "mk_file_system.h"

namespace MK3DE
{
	CD3D9Shader::CD3D9Shader()
	{
	}

	CD3D9Shader::CD3D9Shader(const char* fileName) : 
	CShader(fileName),
		_effect(NULL)
	{

	}

	CD3D9Shader::~CD3D9Shader()
	{
		SAFE_RELEASE(_effect);
	}

	BOOL CD3D9Shader::TechniqueBegin(const char* techName, DWORD& passNum)
	{
		D3DXHANDLE handle = (D3DXHANDLE)techName;
		HRESULT hr = _effect->SetTechnique(handle);
		MK_PROCESS_COM_ERROR(hr);

		hr = _effect->Begin((UINT*)&passNum, 0);
		MK_PROCESS_COM_ERROR(hr);

		return TRUE;
Exit0:
		return FALSE;
	}

	BOOL CD3D9Shader::PassBegin(DWORD idx)
	{
		HRESULT hr = _effect->BeginPass(idx);
		MK_PROCESS_COM_ERROR(hr);

		return TRUE;
Exit0:
		return FALSE;
	}

	BOOL CD3D9Shader::PassEnd()
	{
		HRESULT hr = _effect->EndPass();
		MK_PROCESS_COM_ERROR(hr);

		return TRUE;
Exit0:
		return FALSE;
	}

	BOOL CD3D9Shader::TechniqueEnd()
	{
		HRESULT hr = _effect->End();
		MK_PROCESS_COM_ERROR(hr);

		return TRUE;
Exit0:
		return FALSE;
	}

	BOOL CD3D9Shader::SetFloatArray(const char* name, float* value, DWORD count)
	{
		MK_PROCESS_ERROR(_effect);

		HRESULT hr = _effect->SetFloatArray(name, value, (UINT)count);
		MK_PROCESS_COM_ERROR(hr);

		return TRUE;
Exit0:
		return FALSE;
	}

	BOOL CD3D9Shader::SetMatrix(const char* name, const D3DXMATRIX* mat)
	{
		MK_PROCESS_ERROR(_effect);

		HRESULT hr = _effect->SetMatrix(name, mat);
		MK_PROCESS_COM_ERROR(hr);

		return TRUE;
Exit0:
		return FALSE;
	}

	BOOL CD3D9Shader::SetTexture(const char* name, CTexture2D* texture)
	{
		MK_PROCESS_ERROR(_effect);

		CD3D9Texture2D* tex = (CD3D9Texture2D*)texture;
		LPDIRECT3DTEXTURE9 d3dtex = NULL;
		if (tex)
			d3dtex = tex->GetD3D9Texture();

		HRESULT hr = _effect->SetTexture(name, d3dtex);
		MK_PROCESS_COM_ERROR(hr);

		return TRUE;
Exit0:
		return FALSE;
	}

	BOOL CD3D9Shader::SetTexture(const char* name, CTexture3D* texture)
	{
		MK_PROCESS_ERROR(_effect);

		CD3D9Texture3D* tex = (CD3D9Texture3D*)texture;
		LPDIRECT3DVOLUMETEXTURE9 d3dtex = NULL;
		if (tex)
			d3dtex = tex->GetD3D9Texture();

		HRESULT hr = _effect->SetTexture(name, d3dtex);
		MK_PROCESS_COM_ERROR(hr);

		return TRUE;
Exit0:
		return FALSE;
	}

	BOOL CD3D9Shader::Load()
	{
		BOOL ret = FALSE;
		CMemoryBlock block;

		std::string root = GetEngine()->GetFileSystem()->GetRoot();
		std::string path = root + _fileName;
		ret = GetEngine()->GetFileSystem()->ReadFile(_fileName.c_str(), &block);
		MK_PROCESS_ERROR(ret);

		CD3D9RenderDevice* rd = (CD3D9RenderDevice*)GetEngine()->GetRenderDevice();
		LPDIRECT3DDEVICE9 d = rd->GetD3DDevice();

		//HRESULT hr = D3DXCreateEffect(d, (void*)block.GetBuffer(), (UINT)block.GetSize(), NULL, NULL, 0, NULL, &_effect, NULL);
		HRESULT hr = D3DXCreateEffectFromFile(d, path.c_str(), NULL, NULL, 0, NULL, &_effect, NULL);
		MK_PROCESS_COM_ERROR(hr);

		return TRUE;
Exit0:
		return FALSE;
	}

	BOOL CD3D9Shader::Reload()
	{
		LPD3DXEFFECT effect = _effect;
		if (Load())
		{
			SAFE_RELEASE(effect);
			return TRUE;
		}

		_effect = effect;
		return FALSE;
	}

	BOOL CD3D9Shader::LoadFromBuffer(const BYTE* buffer, DWORD size)
	{
		BOOL ret = FALSE;

		CD3D9RenderDevice* rd = (CD3D9RenderDevice*)GetEngine()->GetRenderDevice();
		LPDIRECT3DDEVICE9 d = rd->GetD3DDevice();

		HRESULT hr = D3DXCreateEffect(d, (void*)buffer, (UINT)size, NULL, NULL, 0, NULL, &_effect, NULL);
		MK_PROCESS_COM_ERROR(hr);

		return TRUE;
Exit0:
		return FALSE;
	}
}